package com.atomscat.lottery.service;

import com.atomscat.lottery.entity.db.LotteryActivityEntity;
import com.atomscat.lottery.entity.db.LotteryRecordEntity;
import com.atomscat.lottery.entity.vo.request.DrawLotteryRequest;
import com.atomscat.lottery.entity.vo.request.LotteryActivityRequest;
import com.atomscat.lottery.entity.vo.request.PageLotteryActivityRequest;
import com.atomscat.lottery.entity.vo.request.UpdateLotteryActivityRequest;
import com.atomscat.lottery.entity.vo.response.LotteryRecordResponse;
import com.atomscat.lottery.repository.LotteryActivityRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
@Service
@RequiredArgsConstructor
public class LotteryActivityService {
    private final WxMpService wxService;
    private final LotteryService lotteryService;
    private final LotteryActivityRepository lotteryActivityRepository;
    private final LotteryActivityUserService lotteryActivityUserService;
    /**
     * Creates a new lottery activity.
     *
     * @param lotteryActivityRequest the request object containing details of the lottery activity to be created
     * @return true if the lottery activity is successfully created, false otherwise
     */
    public Boolean createLotteryActivity(LotteryActivityRequest lotteryActivityRequest) {
        LotteryActivityEntity lotteryActivityEntity = new LotteryActivityEntity();
        lotteryActivityEntity.setName(lotteryActivityRequest.getName());
        lotteryActivityEntity.setDescription(lotteryActivityRequest.getDescription());
        lotteryActivityEntity.setStatus("unpublished");
        lotteryActivityEntity.setLotteryType(lotteryActivityRequest.getLotteryType());
        lotteryActivityEntity.setMaxParticipants(lotteryActivityRequest.getMaxParticipants());
        lotteryActivityRepository.save(lotteryActivityEntity);
        return lotteryActivityEntity.getId() != null;
    }

    /**
     * Updates an existing lottery activity.
     *
     * @param lotteryActivityRequest the request object containing updated details of the lottery activity
     * @return true if the lottery activity is successfully updated, false otherwise
     */
    public Boolean updateLotteryActivity(UpdateLotteryActivityRequest lotteryActivityRequest) {
        lotteryActivityRepository.findById(lotteryActivityRequest.getId()).map(lotteryActivityEntity -> {
            lotteryActivityEntity.setName(lotteryActivityRequest.getName());
            lotteryActivityEntity.setDescription(lotteryActivityRequest.getDescription());
            lotteryActivityEntity.setLotteryType(lotteryActivityRequest.getLotteryType());
            lotteryActivityEntity.setMaxParticipants(lotteryActivityRequest.getMaxParticipants());
            return lotteryActivityRepository.saveAndFlush(lotteryActivityEntity);
        });
        return true;
    }

    /**
     * Updates the status of a lottery activity to "recruiting".
     *
     * @param id the unique identifier of the lottery activity to be updated
     * @return true if the operation is successful
     */
    public Boolean recruitingLotteryActivity(Long id) {
        lotteryActivityRepository.findById(id).map(lotteryActivityEntity -> {
            if (lotteryActivityEntity.getStatus().equals("unpublished")) {
                lotteryActivityEntity.setStatus("recruiting");
                try {
                    // Event(subscribe): EventKey(qrscene_ + id)
                    // Event(SCAN): EventKey(id)
                    WxMpQrCodeTicket wxMpQrCodeTicket = wxService.getQrcodeService().qrCodeCreateLastTicket(String.valueOf(lotteryActivityEntity.getId()));
                    lotteryActivityEntity.setQrCodeUrl(wxMpQrCodeTicket.getUrl());
                    // https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={{Ticket}}
                    lotteryActivityEntity.setQrCodeTicket(wxMpQrCodeTicket.getTicket());
                } catch (WxErrorException e) {
                    throw new RuntimeException(e);
                }
            }
            return lotteryActivityRepository.saveAndFlush(lotteryActivityEntity);
        });
        return true;
    }

    /**
     * Activates a lottery activity by updating its status to "active".
     *
     * @param id the unique identifier of the lottery activity to be activated
     * @return true if the operation is successful
     */
    public Boolean activeLotteryActivity(Long id) {
        lotteryActivityRepository.findById(id).map(lotteryActivityEntity -> {
            if (lotteryActivityEntity.getStatus().equals("recruiting")) {
                lotteryActivityEntity.setStatus("active");
                lotteryService.deleteParticipant(lotteryActivityEntity.getId());
                lotteryActivityUserService.getLotteryActivityUsers().forEach(lotteryActivityUserEntity -> {
                    lotteryService.addParticipant(lotteryActivityUserEntity.getActivityId(), String.valueOf(lotteryActivityUserEntity.getUserId()));
                });
                lotteryActivityEntity.getLotteryPrizes().stream().forEach(prize -> {
                    lotteryService.deletePrize(lotteryActivityEntity.getId(), String.valueOf(prize.getId())).subscribe(count -> {
                        for (int i = 0; i < prize.getPrizeQuantity(); i++) {
                            lotteryService.addPrize(lotteryActivityEntity.getId(), prize.getId(), String.valueOf(i));
                        }
                    });

                });
            }
            return lotteryActivityRepository.saveAndFlush(lotteryActivityEntity);
        });
        return true;
    }

    /**
     * Retrieves a paginated list of lottery activities based on the provided filter criteria.
     *
     * @param lotteryActivityRequest the request object containing filter criteria such as name, status,
     *                               page number, and page size.
     * @return a paginated list of `LotteryActivityEntity` objects matching the filter criteria.
     */
    public Page<LotteryActivityEntity> lotteryActivityPage(PageLotteryActivityRequest lotteryActivityRequest) {
        LotteryActivityEntity lotteryActivityEntity = new LotteryActivityEntity();
        lotteryActivityEntity.setId(lotteryActivityRequest.getId());
        lotteryActivityEntity.setName(lotteryActivityRequest.getName());
        lotteryActivityEntity.setStatus(lotteryActivityRequest.getStatus());
        PageRequest pageable = PageRequest.of(lotteryActivityRequest.getPageNumber(), lotteryActivityRequest.getPageSize());
        return lotteryActivityRepository.findAll(Example.of(lotteryActivityEntity), pageable);
    }

    public LotteryActivityEntity getLotteryActivityEntity(Long id) {
        return lotteryActivityRepository.findById(id).orElse(null);
    }

    public LotteryRecordResponse drawLottery(DrawLotteryRequest drawLotteryRequest) {
        return lotteryService.drawLottery(drawLotteryRequest.getActivityId(), drawLotteryRequest.getPrizeId());
    }
}
